import { ActionArgHelper } from "GameLoop/Execution/ControlManager/Control/ActionManager/ActionArgHelper";
import { WhiteListManager } from "GameLoop/WorldState/EngineConfig/WhiteListManager";
import { adjacent_dirs } from "utils/constants/moveConstant";
import { cache_return } from "utils/decorate/decorate";
import { EntityHelper } from "utils/entity/EntityHelper";
import { PositionHelper } from "utils/position/PositionHelper";
import { UtilsHelper } from "utils/position/UtilsHelper";
 
 
/**
 * 房间的基础功能.
 * 1.维持能量的正常运转
 * 2.维持房间爬的正常数量
 */
export default class CacheExtension extends Room 
{
    private _cacheCreep:Record<number,Creep>={}
    public getStructureById<T extends Structure>(id:Id<T>):T|null
    {
        if((this as any)[`cache_${id}`])
        {
            return (this as any)[`cache_${id}`];
        }
        (this as any)[`cache_${id}`] = Game.getObjectById(id);
        return  (this as any)[`cache_${id}`]
    }
    // 通过缓存取数据
    public getStructures<T extends StructureConstant>(type:T,inverval?:number):ConcreteStructure<T>[]
    {
        if((this as any)[`cache_${type}`])
        {
            return (this as any)[`cache_${type}`];
        }
        if(type == STRUCTURE_POWER_BANK)
        {
            // PowerBlank
            const powerBank = this.find(FIND_STRUCTURES,{filter:(e)=>e.structureType==STRUCTURE_POWER_BANK});
            (this as any)[`cache_${type}`] =powerBank;
            return  (this as any)[`cache_${type}`]
        }
        const cachestructure = this.getWorld().PollStructure(this.name);
        if(cachestructure)
        {
            cachestructure.cacheData
            const strctures = cachestructure.getStructure(type);
            if(strctures)
            {
                const tmpstrctures:ConcreteStructure<T>[]=[];
                for(const e of strctures )
                {
                    const tower = Game.getObjectById(e.id) as any as ConcreteStructure<T>;
                    if(tower)
                    {
                        tmpstrctures.push(tower);
                    }
                }
                (this as any)[`cache_${type}`] = tmpstrctures;
                return  (this as any)[`cache_${type}`]
            }
        }
        
        return []
    }
     
    public getConstructSites<T extends BuildableStructureConstant>(type?:T):ConstructionSite<T> []
    {
        if(type)
        {
            if((this as any)[`cache_site_${type}`])
            {
                return (this as any)[`cache_site_${type}`];
            }
            const cachestructure = this.getWorld().PollConstructSites(this.name);
            if(cachestructure)
            {
                const strcturesites = cachestructure.getStructureSite(type);
                if(strcturesites)
                {
                    (this as any)[`cache_site_${type}`] = strcturesites;
                    return  (this as any)[`cache_site_${type}`]
                }
            }
        }
        else 
        {
            if((this as any)[`cache_allsite`])
            {
                return (this as any)[`cache_allsite`];
            }
            const cachestructure = this.getWorld().PollConstructSites(this.name);
            if(cachestructure)
            {
                const allsites = [];
                const caches = cachestructure.getConstructureSiteCaches();
                for(const e of caches)
                {
                    const site = Game.getObjectById(e.id) as any as ConstructionSite<T>;
                    if(site)
                    {
                        allsites.push(site);
                    }
                }
                (this as any)[`cache_allsite`] = allsites;
                return (this as any)[`cache_allsite`]
            }
        }
        
        return []
    }
    public getHostileCreeps()
    {
        return this._getHostileCreeps().enemy
    }
    public getFriendCreeps()
    {
        return this._getHostileCreeps().friend
    }
    private _getHostileCreeps()
    {
        const key = `cache_HostileCreep`
        if((this as any)[key])
        {
            return (this as any)[key];
        }
        const creeps=  this.find(FIND_HOSTILE_CREEPS);
        const friends:Creep[]=[];
        for(let i=0;i<creeps.length;i++)
        {
            if(WhiteListManager.IsFriendCreep( creeps[i] ))
            {
                friends.push(creeps[i]);
                creeps.splice(i,1);
                i--;
            }
        }
        (this as any)[key] = {
            friend:friends,
            enemy:creeps
        };
        return (this as any)[key] 
    }

    public getSource()
    {
        const key = `cache_Source`
        if((this as any)[key])
        {
            return (this as any)[key];
        }
        const cache = this.getWorld().PollSource(this.name);
        if(cache)
        {
            const roomObject:Source[]=[];
            for(const e of cache.cacheData )
            {
                const tower = Game.getObjectById(e.id) as any as Source;
                if(tower)
                {
                    roomObject.push(tower);
                }
            }
            (this as any)[key] = roomObject;
            return  (this as any)[key]
        }
        return []
    }
    public  getDeposit():Deposit[]
    {
        const key = `cache_Deposit`
        if((this as any)[key])
        {
            return (this as any)[key];
        }
        const depos = this.find(FIND_DEPOSITS,{filter:(e)=>e.cooldown<=100});
        (this as any)[key]  = depos;
        return depos
    }
    public getMinerial()
    {
        const key = `cache_Minerial`
        if((this as any)[key])
        {
            return (this as any)[key];
        }
        const cache = this.getWorld().PollMinerial(this.name);
        if(cache)
        {
            const roomObject:Mineral[]=[];
            for(const e of cache.cacheData )
            {
                const tower = Game.getObjectById(e.id) as any as Mineral;
                if(tower)
                {
                    roomObject.push(tower);
                }
            }
            (this as any)[key] = roomObject;
            return  (this as any)[key]
        }
        return []
    }

    public getResource(type:ResourceConstant)
    {
        const key = `cache_Resource_${type}`
        if((this as any)[key])
        {
            return (this as any)[key];
        }
        const cache = this.getWorld().PollResource(this.name);
        if(cache)
        {
            const roomObject:Resource[]=[];
          
            
            const resource = cache.getResource(type);
            if(resource)
            {
                for(const e of resource )
                {
                    const obj = Game.getObjectById(e.id) as any as Resource;
                    if(this.getType() ==1)
                    {
                        const spawn = this.getEntity("SpawnEntity");
                        if(obj && spawn.getContainePos().every(e=>!e.isEqualTo(obj.pos)))
                        {
                            roomObject.push(obj);
                        }
                    }
                    else 
                    {
                        if(obj  )
                        {
                            roomObject.push(obj);
                        }
                    }
                   
                }
                (this as any)[key] = roomObject;
                return  (this as any)[key]
            }
        }
        return []
    }
    
    /**
     * 能量存的地方 每10tick更新一次
     * @returns 
     */
    public getEnergyStore()
    {
        const heap = this.getNodeHeap<RoomHeap>();
        if(!heap.lastupdate || Game.time-heap.lastupdate>10)
        {
            // 需要更新
            const storeObjects = EntityHelper.getTransferObject2(this,500);
            heap.energyStore = storeObjects?.id;
            // this.log(`warn`,'更新能量仓库',heap.lastupdate)
            heap.lastupdate = Game.time;
           
        }
        return heap.energyStore
    }

    public  getResourceObject<T extends TakeType>(type:T,creep:Creep):ResourceOperator|false
    {
        
        const getBaseResource=():ResourceOperator|false=>
        {
            const spawnentity =  this.getEntity("SpawnEntity");
            const containers = spawnentity.getWithdrawObjects({resourceType:RESOURCE_ENERGY,amount:2000});
            if(containers.length>0&& spawnentity.Link && spawnentity.Link.store.getUsedCapacity(RESOURCE_ENERGY)>100)
            {
                for(const e of containers)
                {
                    return {oper:"withdraw",object:e}
                }
            }
            const coreEntity = this.getEntity("CoreEntity");
            const   taskobj  =  coreEntity.getTakeStores({resourceType:RESOURCE_ENERGY,amount:130000})
            if(taskobj.length>0)
            {
                return {oper:"withdraw",object:taskobj[0]}

            }
            return false
        }
        
        if(type == "carry")
        {

            const spawnentity =  this.getEntity("SpawnEntity");
            const containers = spawnentity.getWithdrawObjects({resourceType:RESOURCE_ENERGY,amount:2000});
            if(containers.length>0&& spawnentity.Link && spawnentity.Link.store.getUsedCapacity(RESOURCE_ENERGY)>100)
            {
                for(const e of containers)
                {
                    return {oper:"withdraw",object:e}
                }
            }
            // 2.填充控制器的container
            // 取
            if(containers.length && containers.every(e=>e.store.getUsedCapacity(RESOURCE_ENERGY)==0))
            {
                const mine  = creep.ownerRoom().getEntitys("InnerMineEntity");
                for(const e of mine)
                {
                    const c = e.getContainer();
                    if(c&& c.store.getUsedCapacity(RESOURCE_ENERGY)>creep.store.getFreeCapacity())
                    {
                        return {oper:"withdraw",object:c}
                    }
                }
            }
        }
        else  if (type == "filltask")
        {
            const core = this.getEntity("CoreEntity",creep.memory.OwnerRoom);
            const store = core.getTakeStores({resourceType:RESOURCE_ENERGY,amount:creep.store.getFreeCapacity()})
            if(store.length>0)
            {
                return {oper:"withdraw",object:store[0],}
                // return [ActionArgHelper.actionWithdraw(creep,store[0],[{resourceType:RESOURCE_ENERGY}])]
            }

            const spawnentity = this.getEntity("SpawnEntity",creep.memory.OwnerRoom);
            const ids = spawnentity.getContainer();
            let hasenergy = false;
            for(const id of ids)
            {
                const container = Game.getObjectById(id)
                if(container && container.store.getUsedCapacity(RESOURCE_ENERGY)>creep.store.getFreeCapacity())
                {
                    return {oper:"withdraw",object:container,}
                    //return [ActionArgHelper.actionWithdraw(creep,container,[{resourceType:RESOURCE_ENERGY}])]
                }
                if(container &&container.store.getUsedCapacity(RESOURCE_ENERGY))
                {
                    hasenergy = true;
                }
            }
            if(!hasenergy)
            {
                const mine  =       this.getEntitys("InnerMineEntity");
                for(const e of mine)
                {
                    const c = e.getContainer();
                    if(c&& c.store.getUsedCapacity(RESOURCE_ENERGY)>creep.store.getFreeCapacity())
                    {
                        return {oper:"withdraw",object:c,}
                        // return [ActionArgHelper.actionWithdraw(creep,c,[{resourceType:RESOURCE_ENERGY}])]
                    }
                }
            }
        }
        else  if (type == "porter")
        {

        }
        else 
        {
            // 通用
            return getBaseResource()
        }
        return false;
    }


    public registerCreepPos(creep:Creep)
    {
        
        this._cacheCreep[creep.pos.to1D()] = creep
    }

    public lookForMyCreep(pos:IFVector2)
    {
        return this._cacheCreep[pos.x+pos.y*50]
    }
    public lookForCreep(pos:IFVector2)
    {
        const creep = this.lookForMyCreep(pos);
        if(creep)
        {
            return creep;
        }
        if(creep === false)
        {
            return undefined
        }
        const ret = this.lookForAt(LOOK_CREEPS,pos.x,pos.y);
        if(ret.length)
        {
            this._cacheCreep[   PositionHelper.to1D(pos) ] = ret[0];
        }
        else 
        {
            ret[PositionHelper.to1D(pos) ]== false as any;
        }
        return undefined
    }

    

    public testLookForCreep(pos:RoomPosition)
    {
        let cpu1 = Game.cpu.getUsed();
        for(let i=0;i<100;i++)
        {
            pos.lookFor(LOOK_CREEPS)
        }
        let cpu2 = Game.cpu.getUsed();
        for(let i=0;i<100;i++)
        {
            this.lookForMyCreep(pos);
        }
        let cpu3 = Game.cpu.getUsed();
        this.log("warn",`LookFor[${cpu2-cpu1}]`,`lookForCreep[${cpu3-cpu2}]`)
    }
 
}